根據開發使用到不同的技術,可能會用到 this 或 建構式等更深入的 JS 寫法,函式做為大部分模組化的單位,有更多的細部的功能可以去了解,也可以更深入理解 JS 作為一個函數式程式語言是怎樣的感覺。
//作為函示呼叫
foo();
//作為方法呼叫
obj.foo();
//生成器函示呼叫
const genFoo = foo(); genFoo.next().value;
//作為建構式執行呼叫
let handler = new Foo();
//使用 apply 呼叫
foo.apply();
//使用 call 呼叫
foo.call();
arguments 儲存了傳入的參數有哪些,我們可以用他去做更多參數的處理跟判斷。
但另外需要注意的是,它的資料格式不是陣列,是一個類陣列(Array-Likes),具有 length 屬性,但是並沒有 forEach 陣列方法。
延續前面 call 的使用,可以讓沒有 forEach 方法的 arguments 使用 forEach
function foo() {
return Array.prototype.forEach.call(arguments, (item)=>{
console.log(item)
})
}
我們宣告一個函式,可以使用 length 去抓到他宣告的參數格是有幾筆。而沒有則為 0。
我們再結合兩個東西之後,可以針對更多參數進行判斷,例如以下
function whatever (you, say) {
if (arguments.length < 2) {
console.log(you + ' ' + say);
} else {
console.log(Array.prototype.join.call(arguments).replaceAll(",", " "));
}
}
每當執行函事實,除了呼叫明確提供的實際參數外,暗地裡還有個隱性的形式參數,就叫做 this ,也被傳入函式。這個 this 代表目前與該函式呼叫相關聯的物件,稱之為函式上下文 (function context)。
JavaScript 的 this 形式參數所指向的東西並非根據函示宣告來決定,而是根據「呼叫的形式」來決定。
function hello () {
console.log(this)
}
const foo = {
name: 'Peter',
hello: function(){
console.log(this)
}
}
const Foo = function(name, age){
this.name = name;
this.age = age;
this.hello = function(){
console.log(this)
}
}
let James = new Foo('James', 32)
let Peter = new Foo('Peter', 18)
James.hello()
VM436:5 Foo {name: 'James', age: 32, hello: ƒ}
Peter.hello()
VM436:5 Foo {name: 'Peter', age: 18, hello: ƒ}
James 也可以變成 Andy
James.hello.call({name: 'Andy'})
VM436:5 {name: 'Andy'}
選擇能夠增進程式碼、更清楚易懂的作法。至於實用性答案則是根據參考參數的形式來挑選適當的那一個,若有一堆不相干的變數值、或是以字面值的形式指定,那麼就該使用 call(
),因為可以直接寫進參數理:但若參數值已經放在陣列理了,或是放進陣列裡較為便利,那麼就應該選擇 apply() 。
https://daily.dev/blog/why-do-you-need-to-know-about-array-like-objects
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/call
https://www.w3schools.com/js/js_object_constructors.asp
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor